package cn.jacksigxu.min3halla.recipe.builder;

import cn.jacksigxu.min3halla.recipe.MixingRecipe;
import com.google.gson.JsonObject;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementRewards;
import net.minecraft.advancements.CriterionTriggerInstance;
import net.minecraft.advancements.RequirementsStrategy;
import net.minecraft.advancements.critereon.RecipeUnlockedTrigger;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.recipes.RecipeBuilder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.ItemLike;
import org.jetbrains.annotations.Nullable;

import java.util.function.Consumer;

public class MixingRecipeBuilder implements RecipeBuilder {

    private int ade = 0, bex = 0, pwd = 0, fla = 0, kar = 0;
    private boolean ice = false, age = false, big = false, blend = false;
    private Item output;
    private int count;
    private Ingredient dye = Ingredient.EMPTY;
    private Ingredient extra = Ingredient.EMPTY;
    private final Advancement.Builder advancement = Advancement.Builder.recipeAdvancement();
    @Nullable
    private String group;

    public static MixingRecipeBuilder builder(ItemStack pOutput) {
        return new MixingRecipeBuilder().setOutput(pOutput);
    }

    public static MixingRecipeBuilder builder(ItemLike pOutput) {
        return new MixingRecipeBuilder().setOutput(new ItemStack(pOutput));
    }

    public MixingRecipeBuilder ingredients(int pAde, int pBex, int pPwd, int pFla, int pKar) {
        this.ade = pAde;
        this.bex = pBex;
        this.pwd = pPwd;
        this.fla = pFla;
        this.kar = pKar;
        return this;
    }

    @Override
    public MixingRecipeBuilder unlockedBy(String pCriterionName, CriterionTriggerInstance pCriterionTrigger) {
        this.advancement.addCriterion(pCriterionName, pCriterionTrigger);
        return this;
    }

    @Override
    public MixingRecipeBuilder group(@Nullable String pGroupName) {
        this.group = pGroupName;
        return this;
    }

    @Override
    public Item getResult() {
        return this.output;
    }

    @Override
    public void save(Consumer<FinishedRecipe> pFinishedRecipeConsumer, ResourceLocation pRecipeId) {
        this.ensureValid(pRecipeId);
        this.advancement.parent(ROOT_RECIPE_ADVANCEMENT).addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(pRecipeId)).rewards(AdvancementRewards.Builder.recipe(pRecipeId)).requirements(RequirementsStrategy.OR);
        pFinishedRecipeConsumer.accept(new Result(pRecipeId, this.group == null ? "" : this.group,
                this.ade, this.bex, this.pwd, this.fla, this.kar, this.ice, this.age, this.dye, this.extra, this.blend,
                this.output, this.count, this.big, this.advancement, pRecipeId.withPrefix("recipes/")));
    }

    private void ensureValid(ResourceLocation pId) {
        if (this.advancement.getCriteria().isEmpty()) {
            throw new IllegalStateException("No way of obtaining recipe " + pId);
        }
    }

    public MixingRecipeBuilder ade(int pAde) {
        this.ade = pAde;
        return this;
    }

    public MixingRecipeBuilder bex(int pBex) {
        this.bex = pBex;
        return this;
    }

    public MixingRecipeBuilder pwd(int pPwd) {
        this.pwd = pPwd;
        return this;
    }

    public MixingRecipeBuilder fla(int pFla) {
        this.fla = pFla;
        return this;
    }

    public MixingRecipeBuilder kar(int pKar) {
        this.kar = pKar;
        return this;
    }

    public MixingRecipeBuilder ice() {
        this.ice = true;
        return this;
    }

    public MixingRecipeBuilder age() {
        this.age = true;
        return this;
    }

    public MixingRecipeBuilder dye(Ingredient pDye) {
        this.dye = pDye;
        return this;
    }

    public MixingRecipeBuilder extra(Ingredient pExtra) {
        this.extra = pExtra;
        return this;
    }

    public MixingRecipeBuilder blend() {
        this.blend = true;
        return this;
    }

    public MixingRecipeBuilder big() {
        this.big = true;
        return this;
    }

    private MixingRecipeBuilder setOutput(ItemStack pOutput) {
        this.output = pOutput.getItem();
        this.count = pOutput.getCount();
        return this;
    }

    static class Result implements FinishedRecipe {

        private final ResourceLocation id;
        private final String group;
        private final int ade, bex, pwd, fla, kar;
        private final boolean ice, age;
        private final Ingredient dye;
        private final Ingredient extra;
        private final boolean blend;
        private final Item output;
        private final int count;
        private final boolean big;
        private final Advancement.Builder advancement;
        private final ResourceLocation advancementId;

        public Result(ResourceLocation id, String group, int ade, int bex, int pwd, int fla, int kar, boolean ice, boolean age,
                      Ingredient dye, Ingredient extra, boolean blend, Item output, int count, boolean big, Advancement.Builder advancement, ResourceLocation advancementId) {
            this.id = id;
            this.group = group;
            this.ade = ade;
            this.bex = bex;
            this.pwd = pwd;
            this.fla = fla;
            this.kar = kar;
            this.ice = ice;
            this.age = age;
            this.dye = dye;
            this.extra = extra;
            this.blend = blend;
            this.output = output;
            this.count = count;
            this.big = big;
            this.advancement = advancement;
            this.advancementId = advancementId;
        }

        @Override
        public void serializeRecipeData(JsonObject pJson) {
            if (!this.group.isEmpty()) {
                pJson.addProperty("group", this.group);
            }
            pJson.addProperty("ade", this.ade);
            pJson.addProperty("bex", this.bex);
            pJson.addProperty("pwd", this.pwd);
            pJson.addProperty("fla", this.fla);
            pJson.addProperty("kar", this.kar);
            pJson.addProperty("ice", this.ice);
            pJson.addProperty("age", this.age);
            pJson.addProperty("big", this.big);
            pJson.addProperty("blend", this.blend);

            if (!this.dye.isEmpty()) {
                pJson.add("dye", this.dye.toJson());
            }
            if (!this.extra.isEmpty()) {
                pJson.add("extra", this.extra.toJson());
            }

            JsonObject output = new JsonObject();
            output.addProperty("item", BuiltInRegistries.ITEM.getKey(this.output).toString());
            if (this.count > 1) {
                output.addProperty("count", this.count);
            }
            pJson.add("output", output);
        }

        @Override
        public ResourceLocation getId() {
            return this.id;
        }

        @Override
        public RecipeSerializer<?> getType() {
            return MixingRecipe.Serializer.INSTANCE;
        }

        @Nullable
        @Override
        public JsonObject serializeAdvancement() {
            return this.advancement.serializeToJson();
        }

        @Nullable
        @Override
        public ResourceLocation getAdvancementId() {
            return this.advancementId;
        }
    }
}
